Ethereum & Polygon

Fees in Relationship to Network Interest

NOTE: Our Macroeconomic models can be found at:

https://jonahb.xyz/eth_model.html and https://jonahb.xyz/poly_model.html Since we wrote the models in R, they could not be uploaded as a .ipynb

Imports

In [1]:
#imports
import plotly.express as px
import matplotlib.pyplot as plt
import plotly.graph_objects as go
plt.style.use("ggplot")

import pandas as pd
import numpy as np
import scipy
from scipy import stats
from datetime import datetime, timedelta
import seaborn as sns
Bad key "text.kerning_factor" on line 4 in
/Users/jonahburian/anaconda3/lib/python3.6/site-packages/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle.
You probably need to get an updated matplotlibrc file from
https://github.com/matplotlib/matplotlib/blob/v3.1.3/matplotlibrc.template
or from the matplotlib source distribution
In [ ]:
 

Upload and Organize Data

In [2]:
#transaction data
eth_df_1 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth-fee-data.csv') # in ETH
eth_df_2 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth-fee-usd.csv') # in USD
eth_df = eth_df_1.merge(eth_df_2, left_on='DAY', right_on='DAY') # in both
eth_df['DAY'] = pd.to_datetime(eth_df['DAY'], format='%Y-%m-%d %H:%M:%S')

poly_df_1 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/poly-fee-data.csv') # in MATIC
poly_df_2 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/poly-fee-usd.csv') # in USD
poly_df = poly_df_1.merge(poly_df_2, left_on='DAY', right_on='DAY') # in both
poly_df['DAY'] = pd.to_datetime(poly_df['DAY'], format='%Y-%m-%d %H:%M:%S')


#interest data
#Numbers represent search interest relative to the highest point on the chart for the given region and time. A value of 100 is the peak popularity for the term. A value of 50 means that the term is half as popular. A score of 0 means there was not enough data for this term.
crypto_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Cryptocurrency_Interest.csv')
crypto_interest_df["Week"] = pd.to_datetime(crypto_interest_df['Week'], format='%m/%d/%y')

ethereum_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Ethereum_Interest.csv')
ethereum_interest_df["Week"] = pd.to_datetime(ethereum_interest_df['Week'], format='%m/%d/%y')

poly_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Polygon_Interest.csv')
poly_interest_df["Week"] = pd.to_datetime(poly_interest_df['Week'], format='%m/%d/%y')

matic_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/MATIC_Interest.csv')
matic_interest_df["Week"] = pd.to_datetime(matic_interest_df['Week'], format='%m/%d/%y')

# price data
ethereum_price = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth.csv') 
ethereum_price['time'] = pd.to_datetime(ethereum_price['time'], format='%Y-%m-%d')

matic_price = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/matic_eth.csv') 
matic_price['time'] = pd.to_datetime(matic_price['time'], format='%Y-%m-%d')

#cut off dates that google trends does not have good data for
cut_off_date = datetime.strptime("01/01/2020", "%d/%m/%Y")
cut_off_date2 = datetime.strptime("03/04/2022", "%d/%m/%Y")


eth_df = eth_df[(eth_df['DAY'] > cut_off_date) & (eth_df['DAY'] < cut_off_date2)]
poly_df = poly_df[(poly_df['DAY'] > cut_off_date) & (poly_df['DAY'] < cut_off_date2)]
crypto_interest_df = crypto_interest_df[(crypto_interest_df['Week'] > cut_off_date) & (crypto_interest_df['Week'] < cut_off_date2)]
ethereum_interest_df = ethereum_interest_df[(ethereum_interest_df['Week'] > cut_off_date) & (ethereum_interest_df['Week'] < cut_off_date2)]
poly_interest_df = poly_interest_df[(poly_interest_df['Week'] > cut_off_date) & (poly_interest_df['Week'] < cut_off_date2)]
matic_interest_df = matic_interest_df[(matic_interest_df['Week'] > cut_off_date) & (matic_interest_df['Week'] < cut_off_date2)]
ethereum_price = ethereum_price[(ethereum_price['time'] > cut_off_date) & (ethereum_price['time'] < cut_off_date2)]
matic_price = matic_price[(matic_price['time'] > cut_off_date) & (matic_price['time'] < cut_off_date2)]

#dataframes from last month, year
cut_off_date_month = datetime.strptime("12/04/2021", "%d/%m/%Y")
cut_off_date_year = datetime.strptime("03/04/2021", "%d/%m/%Y")
eth_df_month = eth_df[(eth_df['DAY'] > cut_off_date_month) & (eth_df['DAY'] < cut_off_date2)]
poly_df_month = poly_df[(poly_df['DAY'] > cut_off_date_month) & (poly_df['DAY'] < cut_off_date2)]
eth_df_year = eth_df[(eth_df['DAY'] > cut_off_date_year) & (eth_df['DAY'] < cut_off_date2)]
poly_df_year = poly_df[(poly_df['DAY'] > cut_off_date_year) & (poly_df['DAY'] < cut_off_date2)]

Evolution of Interest Over Time

In [3]:
#normalizing interest
crypto_interest_df["Interest_Z_score"] = (crypto_interest_df["Interest"] - np.mean(crypto_interest_df["Interest"]))/scipy.stats.sem(crypto_interest_df["Interest"])
ethereum_interest_df["Interest_Z_score"] = (ethereum_interest_df["Interest"] - np.mean(ethereum_interest_df["Interest"]))/scipy.stats.sem(ethereum_interest_df["Interest"])
poly_interest_df["Interest_Z_score"] = (poly_interest_df["Interest"] - np.mean(poly_interest_df["Interest"]))/scipy.stats.sem(poly_interest_df["Interest"])
matic_interest_df["Interest_Z_score"] = (matic_interest_df["Interest"] - np.mean(matic_interest_df["Interest"]))/scipy.stats.sem(matic_interest_df["Interest"])
In [4]:
#charting interest over time - normal
# set up plotly figure for normal interest over time
fig = go.Figure()

# add different traces
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Z_score'],
    hovertext=crypto_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Z_score'],
    hovertext=ethereum_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

fig.add_trace(go.Scatter(
    name="MATIC Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Z_score'],
    hovertext=matic_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Z_score'],
    hovertext=poly_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="purple"
    ),
    showlegend=True
))

fig.update_layout(
    title="Normalized Interest",
    xaxis_title="Date",
    yaxis_title="Interest Based on Normalization of Google Interest Score",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [5]:
#charting interest over time - rolling
rolling_val = 10
fig = go.Figure()
# add different traces
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="MATIC Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="purple"
    ),
    showlegend=True
))

fig.update_layout(
    title="Normalized",
    xaxis_title="Date",
    yaxis_title="Interest Based on Normalization of Google Interest Score",
    legend_title="Legend",
    showlegend=True
)

fig.show()

Statistics on Transaction Fees Over Different Periods of Time

  • Important: note the scales (Ethereum scale is way higher)
  • Both chains have greater mean fees and variance has been higher in more recent timeframes
  • Polygon’s variance has increased more in recent months but remains lower than Ethereum when set on comparable scales.
In [6]:
#Ethereum Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(eth_df["AVG_FEE_USD"]), np.mean(eth_df_year["AVG_FEE_USD"]), np.mean(eth_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Mean)
plt.title('Ethereum: Mean Fee USD')
plt.xlabel('Date')
plt.ylabel('Mean Fee USD')
plt.show()
In [7]:
#Ethereum Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(eth_df["AVG_FEE_USD"]), np.var(eth_df_year["AVG_FEE_USD"]), np.var(eth_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Var)
plt.title('Ethereum: Variance of Fee USD')
plt.xlabel('Date')
plt.ylabel('Variance of Fee USD')
plt.show()
In [8]:
#Polygon Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(poly_df["AVG_FEE_USD"]), np.mean(poly_df_year["AVG_FEE_USD"]), np.mean(poly_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Mean)
plt.title('Polygon: Mean Fee USD')
plt.xlabel('Date')
plt.ylabel('Mean Fee USD')
plt.show()
In [9]:
#Polygon Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(poly_df["AVG_FEE_USD"]), np.var(poly_df_year["AVG_FEE_USD"]), np.var(poly_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Var)
plt.title('Polygon: Variance of Fee USD')
plt.xlabel('Date')
plt.ylabel('Variance of Fee USD')
plt.show()

Statistics on Transactions Over Different Periods of Time

  • For both chains, transaction volume has remained roughly constant over time and the variance of transaction volume has decreased.
  • The lower transaction volume on Polygon initially can be attributed to the chain not yet being fully adopted.
  • Conclusion: Supply has remained steady on both chains. This is unsurprising given that there is a limited amount of blockspace and blocks tend to be nearly filled.
In [10]:
#Ethereum Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(eth_df["TOTAL_TRANSACTIONS"]), np.mean(eth_df_year["TOTAL_TRANSACTIONS"]), np.mean(eth_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Mean)
plt.title('Ethereum: Mean Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Mean Transaction Volume')
plt.show()
In [11]:
#Ethereum Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(eth_df["TOTAL_TRANSACTIONS"]), np.var(eth_df_year["TOTAL_TRANSACTIONS"]), np.var(eth_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Var)
plt.title('Ethereum: Variance of Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Variance of Transaction Volume')
plt.show()
In [12]:
#Polygon Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(poly_df["TOTAL_TRANSACTIONS"]), np.mean(poly_df_year["TOTAL_TRANSACTIONS"]), np.mean(poly_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Mean)
plt.title('Polygon: Mean Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Mean Transaction Volume')
plt.show()
In [13]:
#Polygon Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(poly_df["TOTAL_TRANSACTIONS"]), np.var(poly_df_year["TOTAL_TRANSACTIONS"]), np.var(poly_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Var)
plt.title('Polygon: Variance of Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Variance of Transaction Volume')
plt.show()

Comparing Transaction Fees Across Blockchains

In [14]:
#normalize transaction fee data
eth_df["AVG_FEE_USD_Z_SCORE"] = (eth_df["AVG_FEE_USD"] - np.mean(eth_df["AVG_FEE_USD"]))/scipy.stats.sem(eth_df["AVG_FEE_USD"])
poly_df["AVG_FEE_USD_Z_SCORE"] = (poly_df["AVG_FEE_USD"] - np.mean(poly_df["AVG_FEE_USD"]))/scipy.stats.sem(poly_df["AVG_FEE_USD"])
In [15]:
#rolling normalized transaction fees
rolling_val = 30
eth_df['Fee_Rolling'] = eth_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
fig.add_trace(go.Scatter(
    name="Ethereum",
    x=eth_df['DAY'],
    y=eth_df['Fee_Rolling'],
    hovertext=eth_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

poly_df['Fee_Rolling'] = poly_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon",
    x=poly_df['DAY'],
    y=poly_df['Fee_Rolling'],
    hovertext=poly_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

fig.update_layout(
    title="Average Fees over Time (Normalized)",
    xaxis_title="Date",
    yaxis_title="Average Fee (USD)",
    legend_title="Legend",
    showlegend=True
)

fig.show()

Interest and Transaction Fees Over Time

  • Especially after normalization, all interest (based on Google Trends) in trends are relatively the same (with the expectation of the initial adoption in mid-2020 of Polygon where Polygon saw a lot of interest.)
  • Ethereum has more variable fee movement than Polygon and both saw spikes in fees during early-2022. We hypothesise that there was a structural break around January possibly due to market forces.
  • Once combining both normalized interest and normalized transaction fees (USD) over time, no obvious patterns appear (other than the spike in January 2022). More analysis was needed.
In [16]:
#ethereum interest with ethereum transaction fees
#rolling 
rolling_val = 7

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

eth_df['Fee_Rolling'] = eth_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Avg Fee (USD)",
    x=eth_df['DAY'],
    y=eth_df['Fee_Rolling'],
    hovertext=eth_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [17]:
#polygon interest with polygon transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure

matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))


poly_df['Fee_Rolling'] = poly_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Avg Fee (USD)",
    x=poly_df['DAY'],
    y=poly_df['Fee_Rolling'],
    hovertext=poly_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [18]:
#cut off dates before Jan (when there was lots of volatility that skewed data)
cut_off_date = datetime.strptime("01/01/2020", "%d/%m/%Y")
cut_off_date2 = datetime.strptime("01/01/2022", "%d/%m/%Y")
eth_df_prejan = eth_df[(eth_df['DAY'] > cut_off_date) & (eth_df['DAY'] < cut_off_date2)]
poly_df_prejan = poly_df[(poly_df['DAY'] > cut_off_date) & (poly_df['DAY'] < cut_off_date2)]
crypto_interest_df_prejan = crypto_interest_df[(crypto_interest_df['Week'] > cut_off_date) & (crypto_interest_df['Week'] < cut_off_date2)]
ethereum_interest_df_prejan = ethereum_interest_df[(ethereum_interest_df['Week'] > cut_off_date) & (ethereum_interest_df['Week'] < cut_off_date2)]
poly_interest_df_prejan = poly_interest_df[(poly_interest_df['Week'] > cut_off_date) & (poly_interest_df['Week'] < cut_off_date2)]
matic_interest_df_prejan = matic_interest_df[(matic_interest_df['Week'] > cut_off_date) & (matic_interest_df['Week'] < cut_off_date2)]
In [19]:
#ethereum interest with ethereum transaction fees (pre-Jan)
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df_prejan['Interest_Rolling'] = crypto_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df_prejan['Week'],
    y=crypto_interest_df_prejan['Interest_Rolling'],
    hovertext=crypto_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df_prejan['Interest_Rolling'] = ethereum_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df_prejan['Week'],
    y=ethereum_interest_df_prejan['Interest_Rolling'],
    hovertext=ethereum_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

eth_df_prejan['Fee_Rolling'] = eth_df_prejan["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Avg Fee (USD)",
    x=eth_df_prejan['DAY'],
    y=eth_df_prejan['Fee_Rolling'],
    hovertext=eth_df_prejan['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:8: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:21: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:34: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

In [20]:
#Polygon interest with polygon transaction fees (pre-Jan)
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
matic_interest_df_prejan['Interest_Rolling'] = matic_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df_prejan['Week'],
    y=matic_interest_df_prejan['Interest_Rolling'],
    hovertext=matic_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

poly_interest_df_prejan['Interest_Rolling'] = poly_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df_prejan['Week'],
    y=poly_interest_df_prejan['Interest_Rolling'],
    hovertext=poly_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_df_prejan['Fee_Rolling'] = poly_df_prejan["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Avg Fee (USD)",
    x=poly_df_prejan['DAY'],
    y=poly_df_prejan['Fee_Rolling'],
    hovertext=poly_df_prejan['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:8: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:21: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/Users/jonahburian/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:34: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Interest and Price Over Time

In [21]:
#ethereum interest with ethereum transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

ethereum_price["AdrActCnt_Z_SCORE"] = (ethereum_price["AdrActCnt"] - np.mean(ethereum_price["AdrActCnt"]))/scipy.stats.sem(ethereum_price["AdrActCnt"])
ethereum_price['Price_Rolling'] = ethereum_price["AdrActCnt_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Price (USD)",
    x=ethereum_price['time'],
    y=ethereum_price['Price_Rolling'],
    hovertext=ethereum_price['Price_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Prices",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
In [22]:
#polygon interest with polygon transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

matic_price["AdrActCnt_Z_SCORE"] = (matic_price["AdrActCnt"] - np.mean(matic_price["AdrActCnt"]))/scipy.stats.sem(matic_price["AdrActCnt"])
matic_price['Price_Rolling'] = matic_price["AdrActCnt_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Price (USD)",
    x=matic_price['time'],
    y=matic_price['Price_Rolling'],
    hovertext=matic_price['Price_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Prices",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()

In Depth Analysis:

Ethereum: Average Fees & Number of Transaction Over Time

  • The number of transactions appear to remain stable.
  • Average fees are more volatile and every month looks different.
  • This seems to indicate that fee volatility is caused by demand shifts (not supply).
In [23]:
cut_off_date3 = datetime.strptime("31/03/2021", "%d/%m/%Y")
cut_off_date4 = datetime.strptime("01/04/2022", "%d/%m/%Y")

eth_for_plot = eth_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
eth_for_plot = eth_for_plot[(eth_for_plot['DAY'] > cut_off_date3) & (eth_for_plot['DAY'] < cut_off_date4)]
eth_for_plot['day'] = pd.DatetimeIndex(eth_for_plot['DAY']).day
eth_for_plot['month'] = pd.DatetimeIndex(eth_for_plot['DAY']).strftime("%b-%y")
eth_for_plot['month-'] = pd.DatetimeIndex(eth_for_plot['DAY']).month

sns.set_theme(style="dark")
g = sns.relplot(
    data=eth_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=eth_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-23-d20f8df064cb> in <module>
      8 eth_for_plot['month-'] = pd.DatetimeIndex(eth_for_plot['DAY']).month
      9 
---> 10 sns.set_theme(style="dark")
     11 g = sns.relplot(
     12     data=eth_for_plot,

AttributeError: module 'seaborn' has no attribute 'set_theme'
In [ ]:
poly_for_plot = poly_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date3) & (poly_for_plot['DAY'] < cut_off_date4)]
poly_for_plot['day'] = pd.DatetimeIndex(poly_for_plot['DAY']).day
poly_for_plot['month'] = pd.DatetimeIndex(poly_for_plot['DAY']).strftime("%b-%y")
poly_for_plot['month-'] = pd.DatetimeIndex(poly_for_plot['DAY']).month


sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()

Polygon: Average Fees & Number of Transaction Over Time

  • The number of transactions appear to remain stable.
  • Average fees remain stable, except January 2022.
  • This seems to indicate that fee volatility is caused by demand shifts (not supply).
In [ ]:
poly_for_plot = poly_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date3) & (poly_for_plot['DAY'] < cut_off_date4)]
poly_for_plot['day'] = pd.DatetimeIndex(poly_for_plot['DAY']).day
poly_for_plot['month'] = pd.DatetimeIndex(poly_for_plot['DAY']).strftime("%b-%y")
poly_for_plot['month-'] = pd.DatetimeIndex(poly_for_plot['DAY']).month


sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()
In [ ]:
sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="TOTAL_TRANSACTIONS", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="TOTAL_TRANSACTIONS", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Total Transactions")
g.tight_layout()

Ethereum and Polygon Heatmaps: Last 3 months of Transaction Fees (USD)

  • Heat maps, where the darker the color means less volatility show that Ethereum prices are more volatile than Polygon prices in high volatility times.
  • Polygon delivers better on the promise of lower volatility.
In [ ]:
#Ethereum
cut_off_date5 = datetime.strptime("31/12/2021", "%d/%m/%Y")
eth_for_plot = eth_for_plot[(eth_for_plot['DAY'] > cut_off_date5)]
eth_for_plot["AVG_FEE_USD"] = round(eth_for_plot["AVG_FEE_USD"]).astype(int)
eth_for_plot_L = eth_for_plot.pivot("day", "month-", "AVG_FEE_USD")
# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(12, 8))
sns.heatmap(eth_for_plot_L, annot=True, linewidths=.5, ax=ax)
In [ ]:
# Polygon
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date5)]
poly_for_plot_L = poly_for_plot.pivot("day", "month-", "AVG_FEE_USD")
# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(12, 8))
sns.heatmap(poly_for_plot_L, annot=True, linewidths=.5, ax=ax)

Fees vs. Interest Linear Regression

  • Naive linear regressions on average fees versus normalized interest show a positive relationship worth exploring.
In [ ]:
# Ethereum
ethereum_tx_interest_crypto = eth_df[['DAY','AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']].merge(crypto_interest_df, left_on='DAY', right_on='Week')
poly_tx_interest_crypto = poly_df[['DAY','AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']].merge(crypto_interest_df, left_on='DAY', right_on='Week')


tips = sns.load_dataset("tips")
g = sns.jointplot(x="Interest_Z_score", y="AVG_FEE_USD_Z_SCORE", data=ethereum_tx_interest_crypto,
                  kind="reg", truncate=False,
                  color="m", height=7)
In [ ]:
# Polygon
g = sns.jointplot(x="Interest_Z_score", y="AVG_FEE_USD_Z_SCORE", data=poly_tx_interest_crypto,
                  kind="reg", truncate=False,
                  color="m", height=7)

Smooth kernel density with marginal histograms for Fees vs. Interest

In [ ]:
#Ethereum:
sns.set_theme(style="white")

g = sns.JointGrid(data=ethereum_tx_interest_crypto, x="Interest", y="AVG_FEE_USD", space=0)
g.plot_joint(sns.kdeplot,
             fill=True,
             thresh=0, levels=100, cmap="rocket")
g.plot_marginals(sns.histplot, color="#03051A", alpha=1, bins=25)
In [ ]:
# Polygon
g = sns.JointGrid(data=poly_tx_interest_crypto, x="Interest", y="AVG_FEE_USD", space=0)
g.plot_joint(sns.kdeplot,
             fill=True,
             thresh=0, levels=100, cmap="rocket")
g.plot_marginals(sns.histplot, color="#03051A", alpha=1, bins=25)

Ethereum vs Polygon Fees Regression

  • A naive linear regression on the normalized average fees against each other shows that fees between the networks are positively correlated.
  • This may be due to people switching to Polygon and/or some external factor like market movement. The latter is more likely the cause of the majority of the effect.
In [ ]:
e_temp = eth_df[['DAY', 'AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']]
e_temp = e_temp.rename(columns={"AVG_FEE_USD": "ETH_AVG_FEE_USD", "AVG_FEE_USD_Z_SCORE": "ETH_AVG_FEE_USD_Z_SCORE"})
poly_temp = poly_df[['DAY', 'AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']]
poly_temp = poly_temp.rename(columns={"AVG_FEE_USD": "POLY_AVG_FEE_USD", "AVG_FEE_USD_Z_SCORE": "POLY_AVG_FEE_USD_Z_SCORE"})
price_temp = e_temp.merge(poly_temp, left_on='DAY', right_on='DAY') # in both



g = sns.jointplot(x="ETH_AVG_FEE_USD_Z_SCORE", y="POLY_AVG_FEE_USD_Z_SCORE", data=price_temp,
                  kind="reg", truncate=False,
                  color="m", height=7)

Macroeconomic Analysis

NOTE: Our Macroeconomic models can be found at: https://jonahb.xyz/eth_model.html and https://jonahb.xyz/poly_model.html . Since we wrote the models in R, they could not be uploaded as a .ipynb